package com.zae.session;

import com.zae.pojo.BorundSql;
import com.zae.pojo.Configuration;
import com.zae.pojo.MapperStatement;
import com.zae.utils.GenericTokenParser;
import com.zae.utils.ParameterMapping;
import com.zae.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {
    public <E> List<E> execute(Configuration configuration, MapperStatement mapperStatement, Object... params) throws Exception{
        //1.获取连接对象
        Connection connection = configuration.getDataSource().getConnection();
        //2.处理sql语句
        String sql = mapperStatement.getSql();
        BorundSql borundSql = dealSql(sql);
        String sqlNow = borundSql.getSql();
        List<ParameterMapping> mappingList = borundSql.getParameterMappingList();
        //3.获取预处理对象
        PreparedStatement preparedStatement = connection.prepareStatement(sqlNow);
        //4.设置参数
        Class<?> classByType = getClassByType(mapperStatement.getParamterType());
        for(int i = 0;i<mappingList.size();i++){
            String content = mappingList.get(i).getContent();
            //根据属性名获取该属性信息
            Field declaredField = classByType.getDeclaredField(content);
            //设置暴力访问
            declaredField.setAccessible(true);
            //获取参数里面的值
            Object value = declaredField.get(params[0]);
            //设置参数
            preparedStatement.setObject(i+1,value);
        }
        //5.处理返回结果集
        ResultSet resultSet = preparedStatement.executeQuery();
        Class<?> resultClass = getClassByType(mapperStatement.getResultType());
        List resultList = new ArrayList();
        while (resultSet.next()){
            //生成该类的实例对象
            Object object = resultClass.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for(int i = 1;i<=metaData.getColumnCount();i++){
                //获取列的名称
                String columnName = metaData.getColumnName(i);
                //根据列的名称获取内容
                Object value = resultSet.getObject(columnName);
                //使用反射或内省，完成字段和数据库的映射
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName,resultClass);
                //获取写入方法
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //调用invoke方法，将数据写入实体
                writeMethod.invoke(object,value);
            }
            resultList.add(object);
        }
        return resultList;
    }

    /**
     * 处理sql，将sql中的#{}处理成?,并把#{}里面的字段保存下来
     * @param sourceSql
     * @return
     */
    private BorundSql dealSql(String sourceSql){
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{","}",parameterMappingTokenHandler);
        String targetSql = genericTokenParser.parse(sourceSql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BorundSql borundSql = new BorundSql();
        borundSql.setSql(targetSql);
        borundSql.setParameterMappingList(parameterMappings);
        return borundSql;
    }

    /**
     * 根据类的全路径获取类对象
     * @param path
     * @return
     */
    private Class<?> getClassByType(String path) throws ClassNotFoundException {
        if(path!=null){
            Class<?> aClass = Class.forName(path);
            return aClass;
        }else{
            return null;
        }
    }
}
